/*
    1. 一个连接必须拥有一个能够请求接收与解析上下文的结构，以便在第二次读取时加载上一次的上下文信息
    2. 上下文的类型、结构不能固定，因为服务器支持的协议可能会不断增多不同的协议
    3. 需要有一个容器 来保存不同的上下文结构

    设计一个自己的Any类
        1.是一个容器，保存不同类型数据      Any a   a = 10; a = "abc"  ?
            解决方案： 模板 × 因为实例化对象时，就要指定容器类型【冲突了】
                      嵌套：先设计一个子类，用来保存其他类型数据，
                            Any只保存Holder类的指针，子类placeHolder多态继承,以子类去实例化具体对象
                            说白了，Any类中只有统一的 *Holder，通过父类指针 *Holder可以找到子类对象
*/

#include <iostream>
#include <typeinfo>
#include <cassert>
class Any
{
private:
    class Holder
    {
    public:
        virtual ~Holder() {}
        virtual const std::type_info &type() = 0;
        virtual Holder *clone() = 0;
    };

    template <typename T>
    class PlaceHolder : public Holder
    {
    public:
        PlaceHolder(const T &val)
            : _val(val)
        {
        }
        virtual const std::type_info &type() /*获取子类对象保存的数据类型*/
        {
            return typeid(T); // #include <typeinfo>
        }
        virtual Holder *clone() /*针对当前对象自身，克隆一个新的子类对象*/
        {
            return new PlaceHolder(_val);
        }

    public:
        T _val;
    };

    Holder *_content; /* Any中 只保存Holder指针*/
public:
    Any() : _content(nullptr) {}

    template <typename T>
    Any(const T &val) /*根据给的数据val类型去构造对象*/
        : _content(new PlaceHolder<T>(val))
    {
    }

    Any(const Any &other) /*若other有内容，那么调用克隆函数返回一个父类指针指向的子类对象*/
        : _content(other._content ? other._content->clone() : nullptr)
    {
    }

    template <typename T>
    Any &operator=(const T &val)
    {
        // if(_content != nullptr)
        //     delete _content;
        // _content = new PlaceHolder(val);
        // return *this;
        Any temp(val);
        std::swap(_content, temp._content);
        return *this;
    }
    Any &operator=(const Any &other)
    {
        if (this != &other)
        {
            Any temp(other);
            std::swap(_content, temp._content);
        }
        return *this;
    }

    template <typename T>
    T *Get() /*获取 Holder指向的子类对象所保存的数据类型*/
    {
        assert(typeid(T) == _content->type());
        return &((PlaceHolder<T> *)_content)->_val; /*父类指针强转子类指针，获取子类的_val实例，再取地址*/
    }

    ~Any() { delete _content; }
};

class Test
{
public:
    Test() { std::cout << "构造完毕" << std::endl; }
    Test(const Test &) { std::cout << "拷贝构造完毕" << std::endl; }
    ~Test() { std::cout << "析构完毕" << std::endl; }
};

int main()
{
    Any a;
    a = 10;
    int *pa = a.Get<int>();
    std::cout << *pa << std::endl;

    a = std::string("inhaohoah");
    std::string *ps = a.Get<std::string>();
    std::cout << *ps << std::endl;

    a = Test();
    return 0;
}

/*  这里是针对 C++17 中Any的使用方法示例*/
// #define ANY
#ifdef ANY
#include <any>
#include <type_traits>
#include <utility>
int main()
{
    std::any a;
    a = 10;
    int *pa = std::any_cast<int>(&a);
    std::cout << *pa << std::endl;

    a = std::string("hahah");
    std::string *ps = std::any_cast<std::string>(&a);
    std::cout << *ps << std::endl;
    return 0;
}
#endif